package services

import (
	"cas_central_server/models"
	"sync"
)

type sampleData struct {
	TimeUnixNano int64   `json:"timeUnixNano"`
	Data         float64 `json:"data"`
}

type dacType struct {
	DACName          string
	Connected        bool   // 是否已经与数据中心服务器连接（可用于保证name唯一）
	IP               string // 采集卡所在IP
	Port             int    // 采集卡端口
	Unit             string // 采集卡采集到的数据的单位
	SamplesPerSecond int    // 采集卡每秒采集的样本点数目
	Samples          []sampleData
	Observers        []observer // 新的样本点数据被添加后会通知observers
}

type dacMapType struct {
	data sync.Map
}

// dacDataMap 采集卡-样本点数据的map
var dacDataMap *dacMapType = &dacMapType{}

// list 列出所有dac
func (dacMap *dacMapType) list() []dacType {
	dacs := []dacType{}
	dacMap.data.Range(func(key, value interface{}) bool {
		dacs = append(dacs, value.(dacType))
		return true
	})
	return dacs
}

// exist dac是否存在
func (dacMap *dacMapType) exist(name string) bool {
	_, ok := dacMap.data.Load(name)
	return ok
}

// isConnected dac是否存在并且已经连接
func (dacMap *dacMapType) isConnected(name string) bool {
	dac, ok := dacMap.data.Load(name)
	return ok && dac.(dacType).Connected
}

func (dacMap *dacMapType) get(name string) dacType {
	dac, ok := dacMap.data.Load(name)
	if !ok {
		return dacType{
			DACName:   name,
			Connected: false,
		}
	}
	return dac.(dacType)
}

func (dacMap *dacMapType) setBasicInfo(name string, ip string, port int, unit string, samplesPerSecond int) {
	dac, ok := dacMap.data.Load(name)
	if !ok {
		dacMap.data.Store(name, dacType{
			DACName:          name,
			IP:               ip,
			Port:             port,
			Unit:             unit,
			SamplesPerSecond: samplesPerSecond,
		})
		return
	}
	dacNew := dac.(dacType)
	dacNew.IP = ip
	dacNew.Port = port
	dacNew.Unit = unit
	dacNew.SamplesPerSecond = samplesPerSecond
	dacMap.data.Store(name, dacNew)
}

func (dacMap *dacMapType) setConnectionStatus(name string, connected bool) {
	dac, ok := dacMap.data.Load(name)
	if !ok {
		dacMap.data.Store(name, dacType{
			DACName:   name,
			Connected: connected,
		})
		return
	}
	dacNew := dac.(dacType)
	dacNew.Connected = connected
	dacMap.data.Store(name, dacNew)
}

func (dacMap *dacMapType) appendSample(name string, sample sampleData) {
	// TODO
	// 数据库保存失败处理
	go models.SaveDacSample(name, sample.TimeUnixNano, sample.Data)

	dac, ok := dacMap.data.Load(name)
	if !ok {
		dacMap.data.Store(name, dacType{
			DACName:   name,
			Connected: true,
			Samples:   []sampleData{sample},
		})
		return
	}
	dacNew := dac.(dacType)
	dacNew.Samples = append(dacNew.Samples, sample)
	// 保证Samples中的数据量不超过500个
	if len(dacNew.Samples) > 500 {
		dacNew.Samples = dacNew.Samples[10:]
		for _, observer := range dacNew.Observers {
			observer.reduceIndex(10)
		}
	}
	currentLen := len(dacNew.Samples) - 1
	dacMap.data.Store(name, dacNew)
	for _, observer := range dac.(dacType).Observers {
		// currentLen 此时currentLen为新的点的下标
		go observer.sampleDataUpdate(currentLen)
	}

}

func (dacMap *dacMapType) addObserver(name string, newObserver observer) {
	dac, ok := dacMap.data.Load(name)
	if !ok {
		dacMap.data.Store(name, dacType{
			DACName:   name,
			Connected: false,
			Observers: []observer{newObserver},
		})
		return
	}
	for _, o := range dac.(dacType).Observers {
		if o == newObserver {
			// 已经存在
			return
		}
	}
	dacNew := dac.(dacType)
	dacNew.Observers = append(dacNew.Observers, newObserver)
	dacMap.data.Store(name, dacNew)
}

func (dacMap *dacMapType) removeObserver(name string, toRemove observer) {
	dac, ok := dacMap.data.Load(name)
	if !ok {
		return
	}
	index := -1
	for i, o := range dac.(dacType).Observers {
		if o == toRemove {
			index = i
			break
		}
	}
	if index != -1 {
		dacNew := dac.(dacType)
		dacNew.Observers = append(dacNew.Observers[:index], dacNew.Observers[index+1:]...)
		dacMap.data.Store(name, dacNew)
	}
}
